package com.oig.sys.query.support;


import com.oig.sys.query.constants.ExpressionEnum;
import com.oig.sys.query.support.module.ConditionPropertyExp;
import com.oig.sys.query.support.module.ConditionExp;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;


@Component
public class MongoExpConditionParser implements QueryConditionExpParser {


    /**
     * 查询条件格式：
     * <pre class="code">
     *      "where":
     *          {"$and": [
     *              {"optime":{"$between":[1614528000000,1616256000000]}},
     *              {"price": {$eq: 1.99 }},
     *              {"amt":{$ne: 1.99}},
     *              {"$or":[{"name":{"$like":"%11%"}},{"code":{"$eq":"123"}}]} -- 允许嵌套
     *          ]}
     * </pre>
     * 或者
     * <pre class="code">
     * "where":{"optime":{"$between":[1614528000000,1616256000000]},"price": {$eq: 1.99 }, "amt":{$ne: 1.99}, "$or":{"name":{"$like":"%11%"}, "code":{"$eq":"123"}} }
     *  --不支持这种格式
     * </pre>
     * 对应 sql
     * <pre class="code">
     *  where optime between 1614528000000 and 1616256000000 and price=1.99 and amt!=1.99 and (name like '%11%' or code=123)
     * </pre>
     */
    @SuppressWarnings("unchecked")
    @Override
    public ConditionExp conditionParer(Object conditionExpression) {
        ConditionExp conditionExp = null ;
        if (conditionExpression instanceof Map) {
            //conditionExpression 格式 map<key, List<Map<key,Map<key,List<Map<key,Object>>>>>>
            Map<String,Object> map = (Map<String,Object>) conditionExpression ;
            conditionExp = new ConditionExp() ;
            if (map.keySet().size()==1){
                if (map.containsKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr())){
                    conditionExp.setKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr());
                } else if (map.containsKey(ExpressionEnum.MongoSymbolEnum.OR.getMongoStr())){
                    conditionExp.setKey(ExpressionEnum.MongoSymbolEnum.OR.getMongoStr());
                }
            }
            if (conditionExp.getKey()!=null){
                this.covertObject(conditionExp, map.get(conditionExp.getKey()));
            } else {
                conditionExp.setKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr());
                this.covertMap(conditionExp, map);
            }

        }
        return conditionExp;
    }


    @SuppressWarnings("unchecked")
    private void covertObject(ConditionExp conditionExp, Object obj){
        if (obj instanceof Map){        // value 直接是map 简写情况
            Map<String, Object> map = (Map<String,Object>) obj ;
            this.covertMap(conditionExp, map) ;
        } else if (obj instanceof List){        //value 是list
            List<ConditionPropertyExp> conditionPropertyExpList = new ArrayList<>();
            List<Map<String,Object>> mapList = (List<Map<String,Object>>) obj;
            for (Map<String,Object> map : mapList){ //循环list
                if (map.containsKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr())
                        || map.containsKey(ExpressionEnum.MongoSymbolEnum.OR.getMongoStr()) ){
                    this.covertMap(conditionExp, map);
                } else {
                    conditionPropertyExpList.addAll(this.covertPropertyMap(map));
                }
            }
            conditionExp.setExpList(conditionPropertyExpList);
        }
    }

    @SuppressWarnings("unchecked")
    private void covertMap(ConditionExp conditionExp, Map<String, Object> map){
        List<ConditionPropertyExp> conditionPropertyExpList = new ArrayList<>();
        List<ConditionExp> sonConditionExpList = conditionExp.getInnerCondition();
        for (String key : map.keySet()){
            if (ExpressionEnum.MongoSymbolEnum.AND.getMongoStr().equals(key)
                    || ExpressionEnum.MongoSymbolEnum.OR.getMongoStr().equals(key)) {
                if (sonConditionExpList == null) {
                    sonConditionExpList = new ArrayList<>();
                }
                ConditionExp sonConditionExp = new ConditionExp();
                sonConditionExp.setKey(key);
                this.covertObject(sonConditionExp, map.get(key));
                sonConditionExpList.add(sonConditionExp);
            } else {
                conditionPropertyExpList.addAll(this.covertKeyMap(key, (Map<String, Object>)map.get(key))) ;
            }
        }
        conditionExp.setInnerCondition(sonConditionExpList);
        conditionExp.setExpList(conditionPropertyExpList);
    }




    @SuppressWarnings("unchecked")
    private List<ConditionPropertyExp> covertPropertyMap(Map<String, Object> map){
        List<ConditionPropertyExp> conditionExpList = new ArrayList<>();
        for (String property : map.keySet()){
            conditionExpList.addAll(this.covertKeyMap(property, (Map<String, Object>)map.get(property))) ;
        }
        return conditionExpList;
    }



    private List<ConditionPropertyExp> covertKeyMap(String property, Map<String, Object> map){
        List<ConditionPropertyExp> conditionExpList = new ArrayList<>();
        for (String symbol : map.keySet()) {
            ConditionPropertyExp conditionExp = new ConditionPropertyExp();
            conditionExp.setField(property);
            conditionExp.setSymbol(symbol);
            conditionExp.setValue(map.get(symbol));
            conditionExpList.add(conditionExp) ;
        }
        return conditionExpList;
    }



    public static ConditionExp createAndCondition(String property, String symbol, Object value) {
        ConditionExp cexp = new ConditionExp();
        cexp.setKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr());
        ConditionPropertyExp conditionPropertyExp = new ConditionPropertyExp();
        conditionPropertyExp.setField(property);
        conditionPropertyExp.setSymbol(symbol);
        conditionPropertyExp.setValue(value);
        List<ConditionPropertyExp> expList = new ArrayList<>() ;
        expList.add(conditionPropertyExp) ;
        cexp.setExpList(expList);
        return cexp;
    }

    /**
     * 判断查询条件里是否有最外层and的条件
     */
    @SuppressWarnings("unchecked")
    public static boolean checkAndCondition(Object conditionExpression, String property){
        if(StringUtils.isBlank(property)){
            return false;
        }
        if (!(conditionExpression instanceof Map)) {
            return false;
        }
        Map<String,Object> map = (Map<String,Object>) conditionExpression ;
        if (map.keySet().size()!=1||!map.containsKey(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr())){
            return map.containsKey(property);
        }
        Object obj = map.get(ExpressionEnum.MongoSymbolEnum.AND.getMongoStr()) ;
        if (obj instanceof Map) {        // value 直接是map 简写情况
            Map<String, Object> conMap = (Map<String, Object>) obj;
            return conMap.containsKey(property);
        } else if (obj instanceof List){
            List<Map<String,Object>> conMapList = (List<Map<String,Object>>) obj;
            for (Map<String,Object> conMap : conMapList ){
                if (conMap.containsKey(property)){
                    return true;
                }
            }
        }
        return false;
    }

}
